import { ItemValue } from "./itemvalue";
import { Question } from "./question";
import { Serializer } from "./jsonobject";
import { QuestionFactory } from "./questionfactory";
import { LocalizableString } from "./localizablestring";
import { settings } from "./settings";

/**
 * A Model for a rating question.
 */
export class QuestionRatingModel extends Question {
  private rates: Array<ItemValue>;

  rateValuesChangedCallback: () => void;

  constructor(public name: string) {
    super(name);
    this.rates = this.createItemValues("rates");
    var self = this;
    this.registerFunctionOnPropertyValueChanged("rates", function() {
      self.fireCallback(self.rateValuesChangedCallback);
    });
    this.onPropertyChanged.add(function(sender: any, options: any) {
      if (
        options.name == "rateMin" ||
        options.name == "rateMax" ||
        options.name == "rateStep"
      ) {
        self.fireCallback(self.rateValuesChangedCallback);
      }
    });

    var locMinRateDescriptionValue = this.createLocalizableString(
      "minRateDescription",
      this,
      true
    );
    var locMaxRateDescriptionValue = this.createLocalizableString(
      "maxRateDescription",
      this,
      true
    );
    locMinRateDescriptionValue.onGetTextCallback = function(text) {
      return text ? text + " " : text;
    };
    locMaxRateDescriptionValue.onGetTextCallback = function(text) {
      return text ? " " + text : text;
    };
  }
  public onSurveyLoad() {
    super.onSurveyLoad();
    this.fireCallback(this.rateValuesChangedCallback);
  }
  /**
   * The list of rate items. Every item has value and text. If text is empty, the value is rendered. The item text supports markdown. If it is empty the array is generated by using rateMin, rateMax and rateStep properties.
   * @see rateMin
   * @see rateMax
   * @see rateStep
   */
  public get rateValues(): Array<any> {
    return this.rates;
  }
  public set rateValues(val: Array<any>) {
    this.setPropertyValue("rates", val);
  }
  /**
   * This property is used to generate rate values if rateValues array is empty. It is the first value in the rating. The default value is 1.
   * @see rateValues
   * @see rateMax
   * @see rateStep
   */
  public get rateMin(): number {
    return this.getPropertyValue("rateMin");
  }
  public set rateMin(val: number) {
    if (!this.isLoadingFromJson && val > this.rateMax - this.rateStep)
      val = this.rateMax - this.rateStep;
    this.setPropertyValue("rateMin", val);
  }
  /**
   * This property is used to generate rate values if rateValues array is empty. It is the last value in the rating. The default value is 5.
   * @see rateValues
   * @see rateMin
   * @see rateStep
   */
  public get rateMax(): number {
    return this.getPropertyValue("rateMax");
  }
  public set rateMax(val: number) {
    if (!this.isLoadingFromJson && val < this.rateMin + this.rateStep)
      val = this.rateMin + this.rateStep;
    this.setPropertyValue("rateMax", val);
  }
  /**
   * This property is used to generate rate values if rateValues array is empty. It is the step value. The number of rate values are (rateMax - rateMin) / rateStep. The default value is 1.
   * @see rateValues
   * @see rateMin
   * @see rateMax
   */
  public get rateStep(): number {
    return this.getPropertyValue("rateStep");
  }
  public set rateStep(val: number) {
    if (val <= 0) val = 1;
    if (!this.isLoadingFromJson && val > this.rateMax - this.rateMin)
      val = this.rateMax - this.rateMin;
    this.setPropertyValue("rateStep", val);
  }
  protected getDisplayValueCore(keysAsText: boolean, value: any): any {
    var res = ItemValue.getTextOrHtmlByValue(
      this.visibleRateValues,
      value
    );
    return !!res ? res : value;
  }
  get visibleRateValues(): ItemValue[] {
    if (this.rateValues.length > 0) return this.rateValues;
    var res = [];
    var value = this.rateMin;
    while (
      value <= this.rateMax &&
      res.length < settings.ratingMaximumRateValueCount
    ) {
      res.push(new ItemValue(value));
      value += this.rateStep;
    }
    return res;
  }
  public getType(): string {
    return "rating";
  }
  supportGoNextPageAutomatic() {
    return true;
  }
  public supportComment(): boolean {
    return true;
  }
  public supportOther(): boolean {
    return true;
  }
  /**
   * The description of minimum (first) item.
   */
  public get minRateDescription(): string {
    return this.getLocalizableStringText("minRateDescription");
  }
  public set minRateDescription(val: string) {
    this.setLocalizableStringText("minRateDescription", val);
  }
  get locMinRateDescription(): LocalizableString {
    return this.getLocalizableString("minRateDescription");
  }
  /**
   * The description of maximum (last) item.
   */
  public get maxRateDescription(): string {
    return this.getLocalizableStringText("maxRateDescription");
  }
  public set maxRateDescription(val: string) {
    this.setLocalizableStringText("maxRateDescription", val);
  }
  get locMaxRateDescription(): LocalizableString {
    return this.getLocalizableString("maxRateDescription");
  }
}
Serializer.addClass(
  "rating",
  [
    { name: "hasComment:boolean", layout: "row" },
    {
      name: "commentText",
      serializationProperty: "locCommentText",
      layout: "row"
    },
    {
      name: "rateValues:itemvalue[]"
    },
    { name: "rateMin:number", default: 1 },
    { name: "rateMax:number", default: 5 },
    { name: "rateStep:number", default: 1, minValue: 1 },
    {
      name: "minRateDescription",
      alternativeName: "mininumRateDescription",
      serializationProperty: "locMinRateDescription"
    },
    {
      name: "maxRateDescription",
      alternativeName: "maximumRateDescription",
      serializationProperty: "locMaxRateDescription"
    }
  ],
  function() {
    return new QuestionRatingModel("");
  },
  "question"
);
QuestionFactory.Instance.registerQuestion("rating", name => {
  return new QuestionRatingModel(name);
});
